

#ifndef BUTILS_H_
#define BUTILS_H_

#include "BDefs.h"
#include <arpa/inet.h>
#include <cassert>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <list>
#include <map>
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <pthread.h>
#include <queue>
#include <set>
#include <signal.h>
#include <sstream>
#include <stack>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <vector>
#include <stdexcept>


using namespace std;

#define B_INIT_MASS_BUF_LEN		4096
#define B_INIT_MASS_BUF_DEL_LEN	3072
#ifndef _DEF_INIT_NORM_BUF_LEN_ // Note include guards.
#define _DEF_INIT_NORM_BUF_LEN_
#define INIT_NORM_BUF_LEN		2097152//2048
#endif
#define B_INC_UNIT_LEN			512
#define APP_EVNT_SIG_ALL		-1
#define APP_EVNT_SIG_RES		-2
#define APP_EVNT_SIG_CORE		-3

namespace blueberry
{
			class BBuffer
			{
			public:
				BBuffer(int);
				virtual ~BBuffer();
				inline const char* GetBuffer()
				{
					return z_DataBuffer;
				}
				;//Params - pointer to the buffer, length
				inline int GetBufLen()
				{
					return i_CurrentBufLen;
				}
				;
				inline void Reset()
				{
					z_DataBuffer[0] = 0;
					i_CurrentBufLen = 0;
				}
				;//To reset whole buffer
				void DeleteFromStart(int);//Params - length to be deleted
			protected:
				char * z_DataBuffer;
				int i_CurrentBufLen;
				int i_CurrentMaxBufLen;
			private:
			};

			class BMassBuffer: public BBuffer
			{
			public:
				BMassBuffer();
				virtual ~BMassBuffer();
				void Append(const char*, int);//Params - buffer to be appended, buffer length
			};

			class BNormBuffer: public BBuffer
			{
			public:
				BNormBuffer(int _iInitBufLen = INIT_NORM_BUF_LEN, int _iIncLen = B_INC_UNIT_LEN);
				virtual ~BNormBuffer();
				void Append(const char*, int);
				int i_IncLen;
			};

			class BFixedBuffer: public BBuffer
			{
			public:
				BFixedBuffer();
				~BFixedBuffer();
				void SetBuffer(const char * _zBuffer, int _iBufLen, UInt _uiSeqNo);
				UInt ui_SequenceNumber;
			};


			class UTLHash
			{
			public:
				static ULong RSHash(char * _zKey);
				static ULong JSHash(char * _zKey);
				static ULong PJWHash(char * _zKey);
				static ULong ELFHash(char * _zKey);
				static ULong BKDRHash(char * _zKey);
				static ULong SDBMHash(char * _zKey);
				static ULong DJBHash(char * _zKey);
				static ULong DEKHash(char * _zKey);
				static ULong BPHash(char * _zKey);
				static ULong FNVHash(char * _zKey);
				static ULong APHash(char * _zKey);
			};

			class UTLDateTimeFormatter
			{
			public:
				static void GetTimeStamp(char *, char *, unsigned int);
				static unsigned long ConvertToUnixEpochTime(char *, char *);
				static unsigned long ConvertToUnixEpochTime(int, int, int, int, int, int);
				static string GetTimeBuffer();
				static time_t ConvertToIntTime(char*);//to calculate time from the given string
			};

			class BSystemCalendar
			{
			public:
				static BSystemCalendar & Instance();

				void GetCurrentTimeBySrcId(UInt _uiSrcId, struct tm * _pTm);
				inline int GetGmtOffsetBySrcId(UInt _uiSrcId)
				{
					return ai_TimeOffset[_uiSrcId];
				}
				inline int GetSystemGmtOffset() { return i_SystemGmtOffset; }
				int GetGmtOffsetByTz(string _sTzLocal);

				void Reinit();

			private:
				void Init();
				void SetSystemGmtOffset();
				bool ReInitGmtOffsetByTz(string _sTzLocal, int & _iOffset);

				int i_SystemGmtOffset;
				int i_SystemGmtOffsetCorr;

				int * ai_TimeOffset;
				bool b_AltCnfMode;

				std::map<const char *,int,ltstr> map_TzOffsets;

			protected:
				BSystemCalendar();
				~BSystemCalendar();

			};

			class UTLMStringTokenizer
			{
			public:
				UTLMStringTokenizer(char * zSource, char cDelim);
				UTLMStringTokenizer();

				inline int GetCount()
				{
					return (int) vec_tokens.size();
				}
				;
				char * GetTokenAt(int iIndex);
				int SplitLines(char * zSource);
			private:
				void Split(char * zSource, char cDelim);
				std::vector<char *> vec_tokens;
			};

			class UTLStdStringTokenizer
			{
			public:
				UTLStdStringTokenizer(const string& str, const string& delimiters)
				{
				    // Skip delimiters at beginning.
				    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
				    // Find first "non-delimiter".
				    string::size_type pos     = str.find_first_of(delimiters, lastPos);

				    while (string::npos != pos || string::npos != lastPos)
				    {
				        // Found a token, add it to the vector.
				        tokens.push_back(str.substr(lastPos, pos - lastPos));
				        // Skip delimiters.  Note the "not_of"
				        lastPos = str.find_first_not_of(delimiters, pos);
				        // Find next "non-delimiter"
				        pos = str.find_first_of(delimiters, lastPos);
				    }
				}
				inline UInt GetCount()const{ return tokens.size(); }
				inline string GetStringAt(UInt _uiIndex)const
				{
					return tokens[_uiIndex];
				}
			private:
				vector<string> tokens;
			};

			class UnicodeString
			{
			public:
				UnicodeString(UInt _uiInitLen)
				{
					aus_String = new UShort[_uiInitLen];
					us_StringLen = 0;
				}
				UnicodeString(UnicodeString * _pSrc, UShort _usBegin, UShort _usEnd)
				{
					us_StringLen = (UShort) (_usEnd - _usBegin);
					aus_String = new UShort[us_StringLen];
					memcpy(aus_String, _pSrc->aus_String + _usBegin, us_StringLen * 2);
				}
				void Append(UShort _usValue)
				{
					aus_String[us_StringLen++] = _usValue;
				}
				void Print()
				{
					for (UShort us = 0; us < us_StringLen; ++us)
					{
						std::cout << aus_String[us] << std::endl;
					}
				}
				~UnicodeString()
				{
					delete[] aus_String;
				}
				UShort * aus_String;
				UShort us_StringLen;
			};

			class UTLUnicodeStringTokenize
			{
			public:
				UTLUnicodeStringTokenize(UnicodeString * _pStr, UShort usDelim);
				UTLUnicodeStringTokenize();
				~UTLUnicodeStringTokenize();

				inline int GetCount()
				{
					return (int) vec_tokens.size();
				}
				;
				UnicodeString * GetTokenAt(int iIndex);
				typedef std::vector<UnicodeString *> T_VEC_USTR;
			private:
				void Split(UnicodeString * _pStr, UShort _usDelim);
				T_VEC_USTR vec_tokens;
			};

			class IPAddrConverter
			{
			public:
				IPAddrConverter();
				UInt GetIPAdderValue(char * _zIPAddr);
				void GetIPAddr(char * _zIPAddr, UInt _uiIPAddrValue);
			};

			class ConfigFile
			{
			public:
				ConfigFile(const char* zConfigFile);
				virtual ~ConfigFile();

				const char* GetValue(const char* sTag, bool _bNoExit = false);
				const char* GetValueByFormatting(const char* zFormat, ...);

				std::map<std::string, std::string> map_ConfigValues;

			private:
				std::string trim(std::string const& source, char const* delims = " \t\r\n");
			};

			class UTLBaseConversion
			{
			public:
				static int Encode(int, char*);
				static int Encode(double, int, char*);
				static int Encode(int, int, char*);
				static int Encode(long long, char*);
				static void EncodePositiveInt(long long, char *);

				static unsigned char DecodeTo64(char);
				static float DecodeFraction(const char*);
				static long long DecodeToLong(const char*);
				static double DecodeToFloat(const char*);

			private:
				static int i_MultiplyValue;

			};

}
namespace blueberry
{
	namespace utl
	{

		namespace que
		{
			/*Memory allocation and deallocation for the data item for UTLQueueContainer must be done externally
			 * Casting or inheritance is up to the developer
			 */
			class BQueueContainer
			{
			public:
				BQueueContainer( void *);//Params - pointer to relevant data item
				BQueueContainer();
				virtual ~BQueueContainer() {}
				void * p_Data;
				BQueueContainer* p_Next;
			};
			class BQueue
			{
			public:
				BQueueContainer * p_Head, * p_Tail;
				BQueue();//Creates an empty queue
				void AddtoQueue( BQueueContainer *);//Params - pointer to the UTLQueueContainer which should be added to the queue tail
			};
			class BQueueHolder
			{
			public:
				BQueueHolder();//To initialize all the members
				virtual ~BQueueHolder();
				void AddtoOwnersQueue( BQueueContainer* );//Params - pointer to the UTLQueueContainer which should be passed from current thread to another thread
				void AddtoOwnersQueueWithLock( BQueueContainer* );
				BQueueContainer* GetFromForeignQueue();//To get from foreign queue
				//Transfer methods
				void TransferToCommonQueue();//Should be run within the host thread
				void TransferFromCommonQueue();//Should be run within the foreign thread

			public:
				BQueue * p_OwnersQueue, * p_CommonQueue, * p_ForeignQueue;
				pthread_mutex_t mut_Lock;


			};
			class BQueueHolder2 : public BQueueHolder
			{
			public:
				BQueueHolder2();
				BQueueHolder2(int _iContPoolSize);
				virtual ~BQueueHolder2();

				void SetPoolSize(int _iContPoolSize);

				void AddtoOwnersQueue( void * );
				void AddtoOwnersQueueWithLock( void * );
				void TransferToCommonQueue();
				void TransferFromCommonQueue();
				void AddtoForeignPool( BQueueContainer* );
				void ClearPool(int _iThershold); // best call at foreign side

				BQueue * p_OwnersPoolQ, * p_CommonPoolQ, * p_ForeignPoolQ;
				pthread_mutex_t mut_PoolLock;
				int i_ContPoolSize;
			};

			class BMultiQueueSource;
			class BMultiQueueHolder
			{
			public:
				BMultiQueueHolder();
				virtual ~BMultiQueueHolder();

				BMultiQueueSource * GetNewSource();
				void TransferToCommonQueue(BMultiQueueSource *);
				void TransferFromCommonQueue();
				BQueueContainer * Pop();

				friend class BMultiQueueSource;
			private:
				std::list<BMultiQueueSource*> lst_SourceQueue;
				BQueue * p_CommonQueue, * p_ForeignQueue;
				pthread_mutex_t mut_Lock;
			};
			class BMultiQueueSource
			{
			public:
				BMultiQueueSource(BMultiQueueHolder *);

				void Push( BQueueContainer * );
				void Flush();
				void PushAndFlush( BQueueContainer * );

				BQueueContainer * p_Head, * p_Tail;
				BMultiQueueHolder * p_Holder;
			};
		}
	} // namespace utl
} // namespace blueberry

namespace blueberry
{
	namespace utl
	{
		namespace app
		{
			/********************************************
			 * Mutex class
			 ********************************************/
			template<class T> class BLock
			{
				T& m_obj; //member
			public:
				// lock
				BLock(T& obj) :	m_obj(obj) { m_obj.Lock();	}
				// unlock
				~BLock()	{ m_obj.Unlock(); }
			};

			class BMutex
			{
			public:
				// default constructor
				BMutex()
				{
					pthread_mutex_init(&m_mMutex, NULL);
				}
				// constructor with recursive param
				BMutex(bool bRecursive)
				{
					if (bRecursive)
					{
						pthread_mutexattr_t attr;
						pthread_mutexattr_init(&attr);
						pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
						pthread_mutex_init(&m_mMutex, &attr);
						pthread_mutexattr_destroy(&attr);
					}
					else
					{
						pthread_mutex_init(&m_mMutex, NULL);
					}

				}

				// destructor
				virtual ~BMutex()
				{
					pthread_mutex_unlock(&m_mMutex);
					pthread_mutex_destroy(&m_mMutex);
				}
				// lock
				int Lock()
				{
					return pthread_mutex_lock(&m_mMutex);
				}
				//unlock
				int Unlock()
				{
					return pthread_mutex_unlock(&m_mMutex);
				}
				// try lock
				int TryLock()
				{
					return pthread_mutex_trylock(&m_mMutex);
				}

			private:
				pthread_mutex_t m_mMutex; // pthread mutex
				BMutex & operator=(const BMutex &) { return *this; } // private = operator
				BMutex(const BMutex &) { } // private copy constructor
			};

			class BAppEventCallback
			{
			public:
				virtual void OnAppEvent(int _iSigNum) { _iSigNum = _iSigNum; }
			};

			class BAppEvent
			{
			protected:
				BAppEvent(const char * _zConfFile);
				virtual ~BAppEvent();

				static void SignalHandler(int);
				static void SignalResHandler(int);
				static void SignalHandler2(int, siginfo_t *, void *);
				static void SignalResHandler2(int, siginfo_t *, void *);

				static void IgnoreSignal(int);
				static void SetSignalDefaultAction(int);

			private:
				static void SetSignal(int _iSigNum, void (*_fpSighndlr)(int));
				static void SetSignalBlocked(int _iSigNum, void (*_fpSighndlr)(int));
				static void SetSignal2(int _iSigNum, void(*_fpSighndlr)(int, siginfo_t *, void *));
				static void SetSignalBlocked2(int _iSigNum, void (*_fpSighndlr)(int, siginfo_t *, void *));
				static void UnSetSignal(int _iSigNum);

				static void PrintSignalInfo(int _iSignal, siginfo_t * _stSigInfo, void * _pUContext);

				static BAppEvent * Sp_Instance;
				static BMutex Smtx_Instance;
				static volatile sig_atomic_t sig_in_action;

				static sigset_t sigt_BlockedSignalSet;
				int i_MaxSigNum;
				static char z_ConfigFile[FILENAME_MAX];
				int i_RestartHour;
				int i_RestartMin;
				int i_RestartDay;

				static std::set<BAppEventCallback*> * ap_EventCb;
				std::set<BAppEventCallback*> set_RestartCb;
			public:
				static BAppEvent * GetInstance(const char * _zConfFile = "../config/config.ini");
				void CheckRestart();
				void ForceRestart(const char * _zReason, int _iWaitIntvl = 5);
				void RegisterForEvent(int _iSigNum, BAppEventCallback * _pCb);
				void SetRestartTime(int _iDay, int _iHour, int _iMin);
			};
		}
	}
}

#endif /* BUTILS_H_ */
